﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;

namespace Cepheus
{
    public class WorkstationAgent : NativeWindow, IDisposable
    {
        #region Win32 imports

        const int NOTIFY_FOR_THIS_SESSION = 0;
        const int NOTIFY_FOR_ALL_SESSIONS = 1;


        const int WM_WTSSESSION_CHANGE = 0x2b1;

        const int WTS_SESSION_LOCK = 0x7;
        const int WTS_SESSION_UNLOCK = 0x8;


        [DllImport("WtsApi32.dll")]
        private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)]int dwFlags);
        [DllImport("WtsApi32.dll")]
        private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);

        #endregion

        #region events

        public event EventHandler WorkStationUnlocked;
        public event EventHandler WorkStationLocked;
        public event EventHandler<ErrorEventArgs> ErrorOccured;

        protected virtual void OnWorkStationLocked(EventArgs e)
        {
            EventHandler workStationLocked = WorkStationLocked;
            if (workStationLocked != null)
            {
                workStationLocked(this, e);
            }
        }

        protected virtual void OnWorkStationUnlocked(EventArgs e)
        {
            EventHandler workStationUnlocked = WorkStationUnlocked;
            if (workStationUnlocked != null)
            {
                workStationUnlocked(this, e);
            }
        }

        protected virtual void OnErrorOccured(object sender, ErrorEventArgs e)
        {
            EventHandler<ErrorEventArgs> errorOccured = ErrorOccured;
            if (errorOccured != null)
            {
                errorOccured(sender, e);
            }
        }

        #endregion


        public WorkstationAgent(Form parentForm)
        {
            this.AssignHandle(parentForm.Handle);
        }

        /// <summary>
        /// fires ErrorEvents, so declare some Delegates before you call this function!
        /// </summary>
        public void Initialize()
        {
            InitSessionNotification();
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_WTSSESSION_CHANGE)
            {
                if (m.WParam.ToInt32() == WTS_SESSION_UNLOCK)
                {
                    OnWorkStationUnlocked(EventArgs.Empty);
                }
                else if (m.WParam.ToInt32() == WTS_SESSION_LOCK)
                {
                    OnWorkStationLocked(EventArgs.Empty);
                }
            }

            base.WndProc(ref m);
        }

        private void InitSessionNotification()
        {
            if (!WTSRegisterSessionNotification(this.Handle, NOTIFY_FOR_THIS_SESSION))
            {
                OnErrorOccured(this, new ErrorEventArgs(new Exception("RegisterSessionNotification failed")));
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            WTSUnRegisterSessionNotification(this.Handle);
        }

        #endregion
    }

}
